/*
-- IOTA Crypto Core
--
-- 2018 by Thomas Pototschnig <microengineer18@gmail.com>
-- discord: pmaxuw#8292
-- https://gitlab.com/iccfpga-rv
--
-- Permission is hereby granted, free of charge, to any person obtaining
-- a copy of this software and associated documentation files (the
-- "Software"), to deal in the Software without restriction, including
-- without limitation the rights to use, copy, modify, merge, publish,
-- distribute, sublicense, and/or sell copies of the Software, and to
-- permit persons to whom the Software is furnished to do so, subject to
-- the following conditions:
-- 
-- The above copyright notice and this permission notice shall be
-- included in all copies or substantial portions of the Software.
-- 
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWAR
*/

#ifndef TROIKAFPGA_H_
#define TROIKAFPGA_H_

#include "troika/troika.h"
#include "fpga/troika.h"

#define FPGA_TROIKA_HASHSIZE	16
#define FPGA_TROIKA_STATESIZE	46

// two modes how troika works ... on rate-inputs and -outputs only or on whole state
// first is faster because less copying is needed
// perhaps better use OOP^^
#define FPGA_TROIKA_WORK_ON_WHOLE_STATE

class TroikaFPGA : public Troika {

private:
	uint32_t m_stateCompressed[46];
	uint32_t m_message[61];


protected:

#ifndef FPGA_TROIKA_WORK_ON_WHOLE_STATE
	virtual void TroikaSqueeze(Trit *hash, unsigned long long hash_length, unsigned int rate, Trit *state, unsigned long long num_rounds);
#endif
	virtual void TroikaPermutation(uint32_t num_rounds);

	uint32_t troikaStateToBCT(uint32_t* trits, int len = 16);
	void troikaBCTToState(uint32_t bct, uint32_t*, int len = 16);
	void TroikaAbsorb(unsigned int rate, const Trit *message, uint32_t message_length, uint32_t num_rounds);
	void troikaConvertState(uint32_t* state_bct, uint32_t* trits, int size = 729);
	void troikaConvertStateBack(uint32_t* trits, uint32_t* state_bct, int size = 729);
	uint32_t* getAlignedMessage(const Trit* message, int size);
	void TroikaSqueeze(Trit *hash, uint32_t hash_length, unsigned int rate, uint32_t num_rounds);
public:
	void importMessage(uint32_t* message, uint32_t rate);
	bool memoryLoopTest();
	virtual void TroikaVarRounds(Trit *out, unsigned long long outlen, const Trit *in, unsigned long long inlen, unsigned long long num_rounds);

	virtual void doTroika(Trit *out, unsigned long long outlen, const Trit *in, unsigned long long inlen);


};


#endif /* TROIKAFPGA_H_ */
